package main

import "fmt"

//TODO : Exam1
func exam1() {
	fmt.Println(add(8, 7))
	fmt.Println(subtraction(8, 7))
	fmt.Println(multiplication(2, 3, 5, 10))
}

func add(number1 int, number2 int) (number3 int) {
	number3 = number1 + number2
	return
}

func subtraction(number1, number2 int) int {
	number3 := number1 - number2
	return number3
}

func multiplication(number ...int) int {
	total := 1

	for _, v := range number {
		total *= v
	}
	return total
}

//TODO : Exam2
func exam2() {
	//f1为函数地址
	f1 := func(x, y int) int {
		z := x + y
		return z
	}
	fmt.Println(f1)
	fmt.Println(f1(5, 6))

	//直接创建匿名函数并运行
	f2 := func(x, y int) int {
		z := x + y
		return z
	}(5, 6)
	fmt.Println(f2)

	//直接创建匿名函数并运行(无参数的形式)  ()调用匿名函数
	func() {
		fmt.Println(5 + 6)
	}()
}

//TODO : Exam3
func exam3() {
	n1 := number1(7)
	fmt.Println(n1(8))

	n2 := number2()
	n2()
}

func number1(x int) func(y int) int {
	return func(y int) int {
		return x + y
	}
}

func number2() func() {
	return func() {
		fmt.Println("Hello World!")
	}
}

//TODO : Exam4
func exam4(val int) int {
	if val > 0 {
		return val + exam4(val-1)
	} else {
		return val
	}
}

/*栈空间变化(堆栈从左到右，增加到一个峰值后再计算从右到左缩小)
exam4(5)
5 + exam4(4)
5 + (4 + exam4(3))
5 + (4 + (3 + exam4(2)))
5 + (4 + (3 + (2 + exam4(1))))
5 + (4 + (3 + (2 + 1)))
5 + (4 + (3 + 3))
5 + (4 + 6)
5 + 10
15
*/

//TODO : Exam5
func exam5(val int, total int) int {
	if val > 0 {
		return exam5(val-1, total+val)
	} else {
		return total
	}
}

/*栈空间变化
exam5(5, 0)
exam5(4, 5)
exam5(3, 9)
exam5(2, 12)
exam5(1, 14)
exam5(0, 15)
15
 */

//TODO : Exam6
func exam6(number int) int {
	total := 0
	for {
		if number > 0 {
			total += number
			number--
		} else {
			break
		}
	}
	return total
}

//TODO : Exam7
type callback func(val, total int) int

func exam7(val int, callback callback) int {
	if val > 0 {
		return callback(val, 0)
	} else {
		return val
	}
}

func addFunc(val int, total int) int {
	if val > 0 {
		return addFunc(val-1, total+val)
	} else {
		return total
	}
}

//不支持 嵌套、重载和默认参数
//可以将函数作为一个值进行赋值
func main() {
	exam1()

	//TODO : 匿名函数(通常不希望再次使用(即只使用一次)的函数可以定义为匿名函数)
	//exam2()

	//TODO : 闭包函数 (函数内在包含子函数，并最终return子函数)
	//exam3()

	//TODO : 递归
	//fmt.Println(exam4(100))

	//TODO : 尾递归
	//fmt.Println(exam5(100, 0))

	//TODO : 迭代
	//fmt.Println(exam6(100))

	//TODO : 回调函数
	//fmt.Println(exam7(100, addFunc))
}
